<?php

declare(strict_types=1);

namespace App\Middleware;

use App\Constants\ErrorCode;
use App\Constants\RedisKey;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

class NoRepeatedRequestMiddleware implements MiddlewareInterface
{
    /**
     * @var ContainerInterface
     */
    protected ContainerInterface $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    private function getLockKey(ServerRequestInterface $request): string
    {
        if (empty($request->getHeaderLine('Authorization'))) {
            return "";
        }
        $userStr = md5($request->getHeaderLine('Authorization'));
        $method = mb_strtolower($request->getMethod(), 'UTF-8');
        $params = $request->getParsedBody();
        $uriStr = $request->getRequestTarget();
        if (!empty($params)) {
            ksort($params);
            $uriStr .= ",p=" . md5(http_build_query($params));
        }

        return RedisKey::getKey(RedisKey::NO_REPEATED_REQUEST_LOCK, $userStr, $method, $uriStr);
    }

    /**
     * Notes: 对同一用户请求的同一接口进行拦截，不允许重复请求
     * User: caijw
     * DateTime: 2021/9/18 14:47
     * @param ServerRequestInterface $request
     * @param RequestHandlerInterface $handler
     * @return ResponseInterface
     */
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $lockKey = $this->getLockKey($request);
        if ($lockKey && !redis()->set($lockKey, 1, ['nx', 'ex' => 2])) {
            abort(ErrorCode::REPEAT_REQUEST);
        }
        try {
            return $handler->handle($request);
        } finally {
            $lockKey && redis()->del($lockKey);
        }
    }
}
